package com.thunisoft.incremental.service.impl;

import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.stereotype.Service;

import com.thunisoft.incremental.common.model.Datasource;
import com.thunisoft.incremental.common.model.DatasourceExample;
import com.thunisoft.incremental.common.model.Group;
import com.thunisoft.incremental.common.model.GroupExample;
import com.thunisoft.incremental.common.model.Task;
import com.thunisoft.incremental.common.model.TaskExample;
import com.thunisoft.incremental.common.model.TaskStatus;
import com.thunisoft.incremental.common.model.TaskStatusExample;
import com.thunisoft.incremental.common.util.DataBaseUtil;
import com.thunisoft.incremental.dao.DatasourceMapper;
import com.thunisoft.incremental.dao.GroupMapper;
import com.thunisoft.incremental.dao.TaskMapper;
import com.thunisoft.incremental.dao.TaskStatusMapper;
import com.thunisoft.incremental.service.ManageService;
import com.thunisoft.incremental.task.ExecuteManager;

import lombok.extern.slf4j.Slf4j;

/**
 * ManageServiceImpl
 *
 * @author Zhang Xin
 * @version v1.0
 * @since 2020/3/27 16:01
 */
@Service
@Slf4j
public class ManageServiceImpl implements ManageService {

    @Autowired
    private DatasourceMapper datasourceMapper;

    @Autowired
    private GroupMapper groupMapper;

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private TaskStatusMapper taskStatusMapper;

    @Autowired
    private ExecuteManager executeManager;

    @Override
    public List<Datasource> getDatasources() {
        DatasourceExample example = new DatasourceExample();
        example.setOrderByClause("(case when dt_updatetime is null then dt_createtime else dt_updatetime end) desc");
        return datasourceMapper.selectByExample(example);
    }

    @Override
    public List<Group> getGroup() {
        GroupExample example = new GroupExample();
        example.setOrderByClause("c_name");
        return groupMapper.selectByExample(example);
    }

    @Override
    public List<Task> getTasksByGroup(String groupId, String searchName) {
        TaskExample example = new TaskExample();
        TaskExample.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(searchName)) {
            criteria.andNameLike(DataBaseUtil.contain(searchName));
        }
        if (StringUtils.isNotBlank(groupId)){
            criteria.andGroupIdEqualTo(groupId);
        }
        example.setOrderByClause("c_name");
        return taskMapper.selectByExample(example);
    }

    @Override
    public List<TaskStatus> getTaskStatus(String groupId, String taskId, Integer status) {
        TaskStatusExample example = new TaskStatusExample();
        TaskStatusExample.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(groupId)) {
            criteria.andGroupIdEqualTo(groupId);
        }
        if (StringUtils.isNotBlank(taskId)) {
            criteria.andTaskIdEqualTo(taskId);
        }
        if (status != null) {
            criteria.andStatusEqualTo(status);
        }
        example.setOrderByClause("dt_start_time desc");
        List<TaskStatus> statusList =  taskStatusMapper.selectByExample(example);
        statusList.sort(Comparator.comparing(e-> e.getEntime()==null ? e.getStartTime() : e.getEntime()));
        Collections.reverse(statusList);
        return statusList;
    }

    @Override
    public void addTask(Task task) {
        if (StringUtils.isNotBlank(task.getId())) {
            task.setUpdatetime(new Date());
            taskMapper.updateByPrimaryKey(task);
        } else {
            task.setCreatetime(new Date());
            task.setId(DataBaseUtil.uuid());
            taskMapper.insert(task);
        }
    }

    @Override
    public void addGroup(Group group) {
        if (StringUtils.isNotBlank(group.getId())) {
            groupMapper.updateByPrimaryKey(group);
        } else {
            group.setId(DataBaseUtil.uuid());
            groupMapper.insert(group);
        }
    }

    @Override
    public void addDatasource(Datasource datasource) {
        if (StringUtils.isNotBlank(datasource.getId())) {
            datasource.setUpdatetime(new Date());
            datasourceMapper.updateByPrimaryKey(datasource);
        } else {
            datasource.setCreatetime(new Date());
            datasource.setId(DataBaseUtil.uuid());
            datasourceMapper.insert(datasource);
        }
    }

    @Override
    public void deleteTask(String taskId) {
        taskMapper.deleteByPrimaryKey(taskId);
    }

    @Override
    public long checkExistTaskByGroup(String groupId) {
        TaskExample example = new TaskExample();
        example.createCriteria().andGroupIdEqualTo(groupId);
        return taskMapper.countByExample(example);
    }

    @Override
    public void deleteGroup(String groupId) {
        GroupExample groupExample = new GroupExample();
        groupExample.createCriteria().andCodeEqualTo(groupId);
        groupMapper.deleteByExample(groupExample);
        TaskExample example = new TaskExample();
        example.createCriteria().andGroupIdEqualTo(groupId);
        taskMapper.deleteByExample(example);
    }

    @Override
    public boolean checkExistTaskByDatasource(String datasourceId) {
        TaskExample example = new TaskExample();
        TaskExample.Criteria criteriaFrom = example.createCriteria();
        criteriaFrom.andDatasourceFromEqualTo(datasourceId);

        TaskExample.Criteria criteriaTo = example.createCriteria();
        criteriaTo.andDatasourceToEqualTo(datasourceId);
        example.or(criteriaTo);
        long num = taskMapper.countByExample(example);
        return num > 0;
    }

    @Override
    public void deleteDataSource(String datasourceId) {
        if (checkExistTaskByDatasource(datasourceId)){
            throw new UnsupportedOperationException("此数据源已被引用无法删除");
        }
        datasourceMapper.deleteByPrimaryKey(datasourceId);
    }

    @Override
    public void executeByGroupId(String groupId) {
        TaskExample taskExample = new TaskExample();
        taskExample.createCriteria().andGroupIdEqualTo(groupId);
        List<Task> tasks = taskMapper.selectByExample(taskExample);
        for (Task task : tasks) {
            TaskStatus status = ExecuteManager.tasks.get(task.getId());
            if (!Optional.ofNullable(status).isPresent()) {
                TaskStatus taskStatus = ExecuteManager.initStatus(groupId, task.getId(), null);
                taskStatusMapper.insert(taskStatus);
                ExecuteManager.tasks.put(task.getId(),taskStatus);
            }
            executeManager.run(task,groupId);
        }
    }

    @Override
    public void executeByTaskId(String taskId) {
        TaskStatus status = ExecuteManager.tasks.get(taskId);
        if (Optional.ofNullable(status).isPresent()) {
            throw new IllegalArgumentException("任务已存在");
        }
        TaskStatus taskStatus = ExecuteManager.initStatus(null, taskId, null);
        ExecuteManager.tasks.put(taskId,taskStatus);
        taskStatusMapper.insert(taskStatus);
        executeManager.run(taskMapper.selectByPrimaryKey(taskId),null);
    }

    @Override
    public boolean testDatabaseConnection(Datasource datasource) throws Exception {
        try {
            jdbcTemplate(datasource).execute("select 1");
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
        return true;
    }

    public JdbcTemplate jdbcTemplate(Datasource datasource) {
        DriverManagerDataSource dataSoueceManager = new DriverManagerDataSource();
        dataSoueceManager.setDriverClassName("org.postgresql.Driver");
        StringBuilder jdbcUrl = new StringBuilder();
        jdbcUrl.append("jdbc:postgresql://");
        jdbcUrl.append(datasource.getIp());
        jdbcUrl.append(":").append(datasource.getPort());
        jdbcUrl.append("/").append(datasource.getDatabase());
        jdbcUrl.append("?charset=utf-8");
        dataSoueceManager.setUrl(jdbcUrl.toString());
        dataSoueceManager.setUsername(datasource.getUsername());
        dataSoueceManager.setPassword(datasource.getPassword());

        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSoueceManager);
        return jdbcTemplate;
    }
}
